package com.ruoyi.flow.flow.rest;

import com.alibaba.fastjson.JSONArray;
import com.ruoyi.flow.activiti.security.SecurityUtils;
import com.ruoyi.flow.common.Page;
import com.ruoyi.flow.core.exception.BadRequestException;
import com.ruoyi.flow.core.exception.NotFoundException;
import com.ruoyi.flow.core.response.Response;
import com.ruoyi.flow.flow.form.FormInfo;
import com.ruoyi.flow.flow.instance.InstanceQueryParam;
import com.ruoyi.flow.flow.workflow.*;
import org.activiti.engine.IdentityService;
import org.activiti.engine.impl.persistence.entity.TaskEntity;
import org.activiti.engine.runtime.ProcessInstance;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.List;
import java.util.Map;
import java.util.Optional;

import static com.google.common.base.Preconditions.checkArgument;

/**
 * 对外Restful Api接口
 *
 * @Author: wtian
 * @Description:
 * @Date: Created in 10:18 2018/8/17
 * @Version: 1.0
 */
@RestController
@RequestMapping("/flow/api")
public class FlowApiController {
    private static final Logger LOGGER = LoggerFactory.getLogger(FlowApiController.class);
    @Autowired
    private IdentityService identityService;

    /**
     * 获取流程定义的发起表单
     *
     * @param definitionKey 流程定义标识
     * @return 如果没有表单内容，返回空字符串
     */
    @RequestMapping(value = "/forms/start/{definitionKey}", method = RequestMethod.GET)
    public Response<FormInfo> getStartProcessForm(@PathVariable String definitionKey) {
        try {
            FormInfo formInfo = FlowService.formService().getStartProcessForm(definitionKey);
            return Response.<FormInfo>success().setData(formInfo);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return Response.error();
    }

    /**
     * 获取流程任务表单
     *
     * @param taskId 任务ID
     * @return
     */
    @RequestMapping(value = "/forms/task/{taskId}", method = RequestMethod.GET)
    public Response<FormInfo> getTaskProcessForm(@PathVariable String taskId) {
        try {
            FormInfo formInfo = FlowService.formService().getTaskProcessForm(taskId);
            return Response.<FormInfo>success().setData(formInfo);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return Response.error();
    }

    /**
     * 启动流程
     *
     * @param assignees     办理人ID，多个用英文,隔开
     * @param definitionKey 模型定义标识
     * @param businessKey   业务标识
     * @param userId        发起流程的用户
     */
    @RequestMapping(value = "/start/{definitionKey}", method = RequestMethod.POST)
    public Response<FlowTask> startProcess(@PathVariable String definitionKey, @RequestParam Optional<String> businessKey, @RequestParam Optional<String> assignees, @RequestParam Optional<String> userId, HttpServletRequest request) {
        String presentedUserId = userId.isPresent() ? userId.get() : SecurityUtils.getCurrentUserId();
        identityService.setAuthenticatedUserId(presentedUserId);

        String presentedBusinessKey = businessKey.isPresent() ? businessKey.get() : null;
        String presentedAssignees = (assignees.isPresent() && StringUtils.isNotEmpty(assignees.get())) ? assignees.get() : null;

        Map<String, Object> variables = FlowUtils.getProcessVariableFromRequest(request);
        try {
            ProcessInstance processInstance = FlowService.instanceService().startProcess(definitionKey, presentedBusinessKey, presentedAssignees, variables);
            TaskEntity executionEntity = FlowService.taskService().getLastExecutionTask(processInstance.getProcessInstanceId());
            return Response.<FlowTask>success().setData(new FlowTask(executionEntity));
        } catch (Exception e) {
            return Response.<FlowTask>error();
        }
    }

    /**
     * 根据当前任务节点获取下一用户任务的节点的办理用户。
     * <br/>如果办理用户是明确的用户或者机构，则直接返回；
     * <br/>如果办理用户是变量（基于{@code ${xxxx} }，则返回跳转到获取用户的URL地址。
     * <br/>如果没有办理用户，返回null
     *
     * @param taskId    当前任务ID
     * @param condition 用户输入的网关判断条件JSON。例如{@code [{varName:"age",varValue:"18"},{varName:"sex",varValue:"boy"}]}。
     *                  <br/>
     *                  此时，如果流程的输出流表达式是{@code ${age>18 && sex=="boy"}}，条件就成立.
     * @return
     */
    @RequestMapping(value = "/assignee", method = RequestMethod.GET)
    public Response<FlowAssignee> getNextAssignee(@RequestParam String taskId, @RequestParam Optional<String> condition, HttpServletResponse response) {
        List<FlowCondition> conditions = null;
        if (condition.isPresent()) {
            try {
                String _condition = condition.get();
                conditions = JSONArray.parseArray(_condition, FlowCondition.class);
            } catch (Exception e) {
                e.printStackTrace();
                return Response.meta().setCode(HttpServletResponse.SC_BAD_REQUEST).setMessage("输出流条件字符串不是合法的JSON格式字符串。").create();
            }
        }
        FlowAssignee flowAssignee = FlowService.taskService().getNextTaskSelectAssignee(taskId, conditions);
        return Response.<FlowAssignee>success().setData(flowAssignee);
    }

    /**
     * 获取任务下一个流程节点信息
     *
     * @param taskId    当前任务ID
     * @param condition 网关输出线路条件
     * @param response
     * @return
     */
    @RequestMapping(value = "/task/{taskId}/next", method = RequestMethod.GET)
    public Response<FlowActivity> getTaskNextActivity(@PathVariable String taskId, @RequestParam Optional<String> condition, HttpServletResponse response) {
        List<FlowCondition> conditions = null;
        if (condition.isPresent()) {
            try {
                String _condition = condition.get();
                conditions = JSONArray.parseArray(_condition, FlowCondition.class);
            } catch (Exception e) {
                e.printStackTrace();
                return Response.meta().setCode(HttpServletResponse.SC_BAD_REQUEST).setMessage("输出流条件字符串不是合法的JSON格式字符串。").create();
            }
        }
        FlowActivity activity = FlowService.activityService().getNextActivityInfo(taskId, conditions);
        return Response.<FlowActivity>success().setData(activity);
    }

    /**
     * 获取开始事件下一个流程节点信息
     *
     * @param definitionKey 流程定义标识
     * @param condition     网关输出线路条件
     * @param response
     * @return
     */
    @RequestMapping(value = "/start/{definitionKey}/next", method = RequestMethod.GET)
    public Response<FlowActivity> getStartNextActivity(@PathVariable String definitionKey, @RequestParam Optional<String> condition, HttpServletResponse response) {
        List<FlowCondition> conditions = null;
        if (condition.isPresent()) {
            try {
                String _condition = condition.get();
                conditions = JSONArray.parseArray(_condition, FlowCondition.class);
            } catch (Exception e) {
                e.printStackTrace();
                return Response.meta().setCode(HttpServletResponse.SC_BAD_REQUEST).setMessage("输出流条件字符串不是合法的JSON格式字符串。").create();
            }
        }
        FlowActivity activity = FlowService.activityService().getNextActivityInfo(FlowService.definitionService().getProcessDefinitionByDefinitionKey(definitionKey).getId(), conditions);
        return Response.<FlowActivity>success().setData(activity);
    }

    /**
     * 获取我的待办列表
     *
     * @param page   分页信息
     * @param userId 用户ID。
     * @return
     */
    @RequestMapping(value = "/tasks/todo", method = RequestMethod.GET)
    public Page<FlowTask> toDoTasks(Page<FlowTask> page, @RequestParam String userId) {
        return FlowService.taskService().getToDoTasks(userId, page);
    }

    /**
     * 获取我的已办列表
     *
     * @param page
     * @param userId
     * @return
     */
    @RequestMapping(value = "/tasks/done", method = RequestMethod.GET)
    public Page<FlowTask> doneTasks(Page<FlowTask> page, @RequestParam String userId) {
        return FlowService.taskService().getDoneTasks(userId, page);
    }

    /**
     * 将任务委托给其他人办理。
     * <br/>
     * 如果任务的原来的执行人由于各种原因，没有时间办理，则可以委托为其他人办理该任务。
     * <br/>
     * 委托成功后，原来的执行人成为任务的{@code owner}，新的委托人成为任务的{@code assignee}
     *
     * @param taskId
     * @param assignee
     * @return
     */
    @RequestMapping(value = "/tasks/{taskId}/delegate/{assignee}", method = RequestMethod.POST)
    public Response<Boolean> delegateTask(@PathVariable String taskId, @PathVariable String assignee) {
        boolean isDelgated = FlowService.taskService().delegateTask(taskId, assignee);
        return Response.<Boolean>success().setData(isDelgated);
    }

    /**
     * 执行任务办理
     *
     * @param taskId    任务ID
     * @param assignees 下一步办理人
     * @param comment   备注信息
     * @param userId    办理用户ID
     * @param request
     * @return
     */
    @RequestMapping(value = "/tasks/{taskId}", method = RequestMethod.POST)
    public Response<FlowTask> doTask(@PathVariable String taskId, @PathVariable String userId, @RequestParam Optional<String> assignees, @RequestParam Optional<String> comment, HttpServletRequest request) {
        Map<String, Object> variables = FlowUtils.getProcessVariableFromRequest(request);
        String _assignees = null;
        if (assignees.isPresent()) {
            _assignees = assignees.get();
        }
        FlowTask flowTask = null;
        try {
            flowTask = FlowService.taskService().doTask(taskId, _assignees, comment.get(), userId, variables);
            return Response.<FlowTask>success().setData(flowTask);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return Response.error();
    }

    /**
     * 获取我的申请列表
     *
     * @param page 分页信息
     * @return
     */
    @RequestMapping(value = "/created")
    public Page<FlowTask> myCreated(Page<FlowTask> page, InstanceQueryParam instanceQueryParam) {
        checkArgument(instanceQueryParam == null || StringUtils.isEmpty(instanceQueryParam.getUserId()), "用户ID不能为空");
        return FlowService.instanceService().instanceList(page, instanceQueryParam);
    }

    /**
     * 获取流程实例的办理历史
     *
     * @param instanceId
     * @return
     */
    @RequestMapping(value = "/history/{instanceId}", method = RequestMethod.GET)
    public Response<List<FlowTask>> history(@PathVariable String instanceId) {
        try {
            List<FlowTask> flowTasks = FlowService.instanceService().getTaskHistoryByProcessInstanceId(instanceId, null).getRows();
            return Response.<List<FlowTask>>success().setData(flowTasks);
        } catch (Exception e) {
            LOGGER.error("获取流程办理历史错误", e);
            return Response.error();
        }
    }

    /**
     * 删除流程实例
     *
     * @param instanceId 流程实例ID
     * @return
     */
    @RequestMapping(value = "/instances/{instanceId}", method = RequestMethod.DELETE)
    @ResponseBody
    public Response<Boolean> deleteInstance(@PathVariable String instanceId) {
        boolean isDeleteSuccessed = false;
        try {
            isDeleteSuccessed = FlowService.instanceService().deleteInstance(instanceId);
        } catch (BadRequestException e) {
            LOGGER.error("流程实例 {} 删除失败", instanceId, e);
        }
        return Response.<Boolean>success().setData(isDeleteSuccessed);
    }

    /**
     * 挂起流程实例
     *
     * @param instanceId
     * @return
     */
    @RequestMapping(value = "/instances/{instanceId}/suspend", method = RequestMethod.POST)
    @ResponseBody
    public Response<Boolean> suspendInstance(@PathVariable String instanceId) {
        boolean isSuspended = FlowService.instanceService().suspendInstance(instanceId);
        return Response.<Boolean>success().setData(isSuspended);
    }

    /**
     * 激活流程实例
     *
     * @param instanceId
     * @return
     */
    @RequestMapping(value = "/instances/{instanceId}/active", method = RequestMethod.POST)
    @ResponseBody
    public Response<Boolean> activeInstance(@PathVariable String instanceId) {
        boolean isActived = FlowService.instanceService().activeInstance(instanceId);
        return Response.<Boolean>success().setData(isActived);
    }

    /**
     * 获取流程图
     *
     * @param instanceId 流程实例ID
     * @param response
     * @throws Exception
     */
    @RequestMapping(value = "/history/graphics/{instanceId}", method = RequestMethod.GET)
    public void readResource(@PathVariable String instanceId, HttpServletResponse response)
            throws Exception {
        // 设置页面不缓存
        response.setHeader("Pragma", "No-cache");
        response.setHeader("Cache-Control", "no-cache");
        response.setDateHeader("Expires", 0);
        FlowService.activityService().getActivitiProccessImage(instanceId, response);
    }

    /**
     * 测试异常
     */
    @RequestMapping(value = "/exception", method = RequestMethod.GET)
    public void exception() {
        throw new NotFoundException("找不到对应的文件");
    }


}
